#include "observerpattern.h"
#include <QObject>
#include <QElapsedTimer>
#include <QDateTime>

// SerialPortSubject 实现
//通过初始化列表 : m_serialCore(serialCore) 将传入的 SerialPortCore 指针赋值给成员变量 m_serialCore
SerialPortSubject::SerialPortSubject(SerialPortCore *serialCore) : m_serialCore(serialCore) {
   // 建立与底层串口核心对象的关联，SerialPortCore 负责实际的串口通信
    connect(m_serialCore, &SerialPortCore::dataReceived, this, &SerialPortSubject::onDataReceived);
}

SerialPortSubject::~SerialPortSubject() {
    closePort();
}
//注册观察者
void SerialPortSubject::registerObserver(Observer *observer) {
    QMutexLocker locker(&m_mutex);
    if (!m_observers.contains(observer)) {
        m_observers.append(observer);
    }
}
//移除观察者
void SerialPortSubject::removeObserver(Observer *observer) {
    QMutexLocker locker(&m_mutex);
    m_observers.removeOne(observer);
}
//通知观察者
void SerialPortSubject::notifyObservers() {
    QMutexLocker locker(&m_mutex);
    for (Observer *observer : m_observers) {
        observer->update(m_currentState);// 调用观察者的update方法，传递当前状态
    }
}
//封装底层串口的打开操作
bool SerialPortSubject::openPort(const QString &portName, qint32 baudRate) {
    return m_serialCore->open(portName, baudRate);
}
//封装关闭打开串口操作
void SerialPortSubject::closePort() {
    m_serialCore->close();
}

qint64 SerialPortSubject::sendData(const QByteArray &data) {
    return m_serialCore->sendData(data);
}

QStringList SerialPortSubject::getAvailablePorts() const {
    return m_serialCore->getAvailablePorts();
}
//当前串口是否打开
bool SerialPortSubject::isPortOpen() const {
    return m_serialCore->isOpen();
}
//获取主题当前状态
SensorState SerialPortSubject::getCurrentState() const {
    QMutexLocker locker(&const_cast<QMutex &>(m_mutex));
    return m_currentState;
}
//收到串口数据后，更新主题的当前状态（m_currentState）
void SerialPortSubject::onDataReceived(const QByteArray &data) {
    QMutexLocker locker(&m_mutex);
    // 更新业务状态
    m_currentState.rawData = data;
    m_currentState.is_valid = !data.isEmpty();
    m_currentState.timestamp = QDateTime::currentMSecsSinceEpoch();

    notifyObservers(); // 收到数据后立即通知观察者
}

// SerialPortObserver 实现
SerialPortObserver::SerialPortObserver(SerialPortSubject *subject,
                                       int timeoutMs,
                                       QObject *parent)
    : QObject(parent), m_subject(subject), m_timeoutMs(timeoutMs)
{
    m_subject->registerObserver(this);
    m_timeoutTimer.setSingleShot(true);//超时定时器单次触发
    connect(&m_timeoutTimer, &QTimer::timeout, this, &SerialPortObserver::onTimeout);
}

SerialPortObserver::~SerialPortObserver() {
    m_subject->removeObserver(this);
}
 //数据更新回调
 void SerialPortObserver::update(const SensorState &state) {
    QMutexLocker locker(&m_mutex);
    if (m_remainingCount <= 0 || !state.is_valid) return;//剩余订阅次数已耗尽||主题发送状态无效

    // 处理数据并转发到UI，转为16进制
    QString dataStr = QString("收到数据: %1").arg(QString(state.rawData.toHex(' ')));
    emit dataUpdated(dataStr);

    // 更新订阅次数
    m_remainingCount--;
    emit subscribeStatusChanged(m_remainingCount);
    m_timeoutTimer.stop(); // 收到数据后停止超时
}

//设置订阅次数
void SerialPortObserver::setSubscribeCount(int count) {
    m_remainingCount = count;
    emit subscribeStatusChanged(m_remainingCount);
}



  // 设置超时时间（动态修改）
void SerialPortObserver::setTimeout(int timeoutMs) {
      QMutexLocker locker(&m_mutex);
      m_timeoutMs = timeoutMs;
      // 若定时器正在运行，立即应用新的超时时间
            if (m_timeoutTimer.isActive()) {
                m_timeoutTimer.start(m_timeoutMs);
            }
        }
//取消订阅
void SerialPortObserver::cancelSubscribe() {

    m_remainingCount = 0;
    m_timeoutTimer.stop();
    emit subscribeStatusChanged(0);
}
//向串口发送数据，并设置只订阅一次响应数据
void SerialPortObserver::sendDataAndSubscribeOnce(const QByteArray &data) {
    QMutexLocker locker(&m_mutex);
    if (m_subject->sendData(data) > 0) {
        m_remainingCount = 1; // 订阅一次
        emit subscribeStatusChanged(1);
        m_timeoutTimer.start(m_timeoutMs); // 启动超时
    }
}

//处理超时
void SerialPortObserver::onTimeout() {
    QMutexLocker locker(&m_mutex);
    if (m_remainingCount > 0) {
        m_remainingCount--;
        emit timeoutOccurred();
        emit subscribeStatusChanged(m_remainingCount);
    }
}
